home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Lib / addr / ap_1adr.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  15.0 KB  |  671 lines

  1. /* ap_1adr.c: parse one address - the heart of the parser */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Lib/addr/RCS/ap_1adr.c,v 6.0 1991/12/18 20:21:24 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Lib/addr/RCS/ap_1adr.c,v 6.0 1991/12/18 20:21:24 jpo Rel $
  9.  *
  10.  * $Log: ap_1adr.c,v $
  11.  * Revision 6.0  1991/12/18  20:21:24  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. /*  ADDRESS PARSER, as per:
  19.  
  20.     "Standard for the Format of ARPA Network Text Messages", D.  Crocker,
  21.     J. Vittal, K. Pogran & D. Henderson, in ARPANET PROTOCOL HANDBOOK, E.
  22.     Feinler & J. Postel (eds), NIC-7104-REV-1, Network Information Center,
  23.     SRI International:  Menlo Park, Ca.  (1978) (NTIS AD-A0038901).
  24.  
  25.     and
  26.  
  27.     "Standard for the Format of Arpa Internet Text Messages", Revised
  28.     by D. Crocker, RFC #822, in INTERNET PROTOCOL TRANSITION WORKBOOK,
  29.     Feinler & J. Postel (eds), Network Information Center, SRI
  30.     International:  Menlo Park, Ca.  (March 1982).
  31.  
  32.     A parsed address is normalized to have routing references placed
  33.     into rfc822-type positioning.
  34.  
  35.     History:
  36.  
  37.     Fall 1977     Bruce Borden:  Initial Design & Coding
  38.     Summer 1979   Dave Crocker:  Completed it & fixed bugs
  39.                  Major reorganization & re-labeling
  40.                  Minor changes to semantics
  41.                  Documentation
  42.     Sept 81       Andy Knutsen   case STPREND -> STPHRSE, to allow comments
  43.                  afterwards
  44.     Sept 81       Dave Crocker   generalized the use of STPHRSE, so that
  45.                  STOKEND occurs only on comma or eof.
  46.                  changed again, to cycle only accepting
  47.                  comments
  48.     Nov 82        Dave Crocker   Converted to accept 822 syntax, while
  49.                  trying also to juggle 733...
  50.     Aug 83        Steve Kille    Fix to STEPER
  51.  
  52.     This module is the real parser, tho it is intended to be co-routined
  53.     with a caller who has something specific to do with ap_1adr's output.
  54.     This is organized so as to make some attempt at limiting core
  55.     consumption.  Fullparse(), however, simply causes a full parse tree to
  56.     be built up in core.
  57.  
  58.     The implementation deviates somewhat from the above specification.
  59.     Deviations and the use of the package are discussed in the companion
  60.     documentation.
  61.  
  62.     The parser's behavior is fairly straightforward.  A singly-linked flat
  63.     list of labelled (lexical) nodes is built up.  Ap_1adr() is used to get
  64.     the next "address segment", which consists of all of the lexical nodes
  65.     up to the end of the next host-phrase (i.e., usually that means up to
  66.     the next comma, semi-colon, or right-angle bracket).
  67.  
  68.     The caller is responsible for initializing state variables, via
  69.     ap_init(), and linking together or using ap_1adr's output segments.
  70.  
  71.     Note that ap_1adr does NOT interpret address text to cause re-directed
  72.     file input.  The caller must do that.  Ap_pshfil() and ap_popfil() can
  73.     be used to save and restore the parse state and acquire the named file.
  74.     The provision for this stacking, given the co-routining, is the reason
  75.     state information is chained through global variables, rather than
  76.     being saved on local (stack) variables.
  77.  
  78.     The amount of input processed on a single call may seem strange.  The
  79.     idea is to try to guess the most common use of the routine.  This is
  80.     presumed to be for address checking, in which acquisition of the MBOX
  81.     and DOMAIN text are most important, with the rest actually being thrown
  82.     away.  It is, of course, possible for the core-limiting heuristic to
  83.     lose if a ridiculous number of groups and personal lists are specified
  84.     in a particular way.  I am assuming that won't happen.
  85. */
  86.  
  87.  
  88.  
  89. #include "util.h"
  90. #include "ap.h"
  91. #include "ap_lex.h"
  92.  
  93.  
  94.  
  95. #define STDOMAIN  0
  96. #define STDTYPE   1
  97. #define STEBAD    2
  98. #define STECMNT   3
  99. #define STEDOMAIN 4
  100. #define STEDONE   5     /* Returned when addresses were NOT found */
  101. #define STEDTYPE  6
  102. #define STEGRP    7
  103. #define STEOK     8     /* Returned when addresses were found */
  104. #define STEPER    9
  105. #define STINIT    10
  106. #define STITER    11
  107. #define STPHRSE   12
  108. #define STSTPER   13
  109.  
  110.  
  111. int  ap_intype  = AP_PARSE_733;         /* default to RFC #733 input */
  112. int  ap_outtype = AP_PARSE_822;         /* default to RFC #822 output */
  113.                     /* with little endian domains */
  114.  
  115. int ap_grplev   = 0;                    /* Group nesting depth */
  116. int ap_perlev   = 0;                    /* <> nesting depth */
  117. int ap_routing;                         /* parsing a route */
  118.  
  119.  
  120.  
  121. #ifdef AP_DEBUG
  122.  
  123. extern AP_ptr           ap_sqinsert ();
  124. extern char             *strdup();
  125. char                    ap_debug=TRUE;     /* True if in debug mode */
  126.  
  127.  
  128. char   *statnam[] = {
  129.     "Domain",       "DTypNam",      "BadEnd",       "CmntEnd",
  130.     "DomainE",      "DoneEnd",      "DTypeE",       "GrpEnd",
  131.     "OKEnd",        "PersEnd",      "Init",         "Iterate",
  132.     "Phrase",       "Persstrt",
  133. };
  134.  
  135.  
  136. char   *typtab[] =
  137. {
  138.     "Nil",          "Comment",      "DataType",     "Domain",
  139.     "DomainLit",    "Word",         "GpEnd",        "GpName",
  140.     "GpStart",      "Mailbox",      "PersonEnd",    "PersonName",
  141.     "PersonStart"
  142. };
  143. #endif
  144. /* */
  145.  
  146.  
  147.  
  148. /* ---------------------  Begin  Routines  -------------------------------- */
  149.  
  150.  
  151. int ap_1adr ()
  152. {
  153.     struct ap_node      base_node;
  154.     AP_ptr              ap_sp = NULLAP,          /* Saved ap node ptr */
  155.                 ap_noname,
  156.             r822_ptr = NULLAP,
  157.             r733_prefptr;
  158.     int                 got_822,
  159.                 noname;
  160.     char                buf[BUFSIZ];
  161.     register int        state;
  162.  
  163.  
  164.     ap_routing = DONE;
  165.     ap_noname = NULL;
  166.     ap_ninit (&base_node);
  167.  
  168.     (void) ap_sqinsert (&base_node, AP_PTR_MORE, ap_pstrt);
  169.  
  170.     for (state = STINIT, got_822 = FALSE, noname = FALSE, r733_prefptr = NULLAP; ; ) {
  171.  
  172.  
  173. #ifdef AP_DEBUG
  174.     if (ap_debug)
  175.         PP_DBG (("=>%d (%s)", state,
  176.                 (state >= 0 && state <= 13) ?
  177.                            statnam[state] : "BOGUS!"));
  178. #endif
  179.  
  180.  
  181.     switch (state) {
  182.     case STITER:
  183.         /* -- Iteration to get real address -- */
  184.         ap_palloc ();
  185.         state = STINIT;
  186.         /* just drop on through -- */
  187.  
  188.     case STINIT:
  189.         /* -- start of parse; empty node -- */
  190.         ap_sp = ap_pcur;
  191.         switch (ap_lex (buf, sizeof(buf))) {
  192.         case LV_WORD:
  193.             ap_pfill (AP_GENERIC_WORD, buf);
  194.             if (noname == TRUE) {
  195.                 /* no name before so copy buf into ap_noname */
  196.                 ap_noname->ap_obvalue =
  197.                     (buf == NULLCP) ? NULLCP : strdup(buf);
  198.                 ap_noname = NULL;
  199.                 noname = FALSE;
  200.             }
  201.             state = STPHRSE;
  202.             break;
  203.  
  204.         case LV_AT:
  205.             if (!got_822) {
  206.                 got_822 = TRUE;
  207.                 r822_ptr = ap_pcur;
  208.             }
  209.             ap_routing = OK;
  210. #ifdef AP_DEBUG
  211.             if (ap_debug)
  212.                 PP_DBG (("(routing)"));
  213. #endif
  214.             state = STDOMAIN;
  215.             break;
  216.  
  217.         case LV_COLON:
  218.             /* -- data type start -- */
  219.             state = STDTYPE;
  220.             break;
  221.  
  222.         case LV_SEMI:
  223.             /* -- group list end -- */
  224.             state = STEGRP;
  225.             break;
  226.  
  227.         case LV_GRTR:
  228.             /* -- personal list end -- */
  229.             state = STEPER;
  230.             break;
  231.  
  232.         case LV_LESS:
  233.             /* -- allow one angle-bracket, here -- */
  234.             ap_pfill (AP_GENERIC_WORD, "");
  235.             noname = TRUE;
  236.             ap_noname = ap_pcur;
  237.             state = STSTPER;
  238.             break;
  239.  
  240.         case LV_FROM:
  241.             /* -- file source -- */
  242.             ap_pfill (AP_DATA_TYPE, "Include");
  243.             state = STITER;
  244.             break;
  245.  
  246.         case LV_COMMENT:
  247.             ap_pfill (AP_COMMENT, buf);
  248.             state = STITER;
  249.             break;
  250.  
  251.         case LV_COMMA:
  252.             /* -- ignore null addresses -- */
  253.             break;
  254.  
  255.         case LV_EOD:
  256.             if (ap_perlev != 0 || ap_grplev != 0)
  257.                 state = STEBAD;
  258.             else
  259.                 state = STEDONE;
  260.             break;
  261.  
  262.         default:
  263.             state = STEBAD;
  264.             break;
  265.         }
  266.  
  267.         continue;
  268.  
  269.  
  270. /* ---------------------------  Ending  --------------------------------- */
  271.  
  272.  
  273.     case STECMNT:
  274.         /* -- accept comments until end -- */
  275.         switch (ap_lex (buf, sizeof(buf))) {
  276.         case LV_COMMENT:
  277.             /* -- just cycle, accepting comments -- */
  278. /*            ap_pfill (AP_COMMENT, buf);*/
  279.             ap_pappend(AP_COMMENT, buf);
  280.             break;
  281.  
  282.         case LV_COMMA:
  283.             state = STEOK;
  284.             break;
  285.  
  286.         case LV_SEMI:
  287.             /* -- group list end -- */
  288.             state = STEGRP;
  289.             break;
  290.  
  291.         case LV_EOD:
  292.             state = STEOK;
  293.             break;
  294.  
  295.         default:
  296.             state = STEBAD;
  297.             break;
  298.         }
  299.  
  300.         continue;
  301.  
  302.  
  303.  
  304.     case STEDONE:
  305.         /* -- end clean; no empty nodes? -- */
  306.         ap_7to8 (r733_prefptr, r822_ptr);
  307.         return (DONE);
  308.  
  309.  
  310.  
  311.     case STEOK:
  312.         /* -- end clean -- */
  313.         ap_7to8 (r733_prefptr, r822_ptr);
  314.         return (OK);
  315.  
  316.  
  317.  
  318.     case STEBAD:
  319.         /* -- end error -- */
  320.         ap_clear();             /* Experimental, DPK, 7 Aug 84 */
  321.         return (NOTOK);
  322.  
  323.  
  324.  
  325.  
  326. /* -----------------------  Gather a phrase  ------------------------------ */
  327.  
  328.  
  329.     case STPHRSE:
  330.         /* -- phrase continuation; empty node -- */
  331.         switch (ap_lex (buf, sizeof(buf))) {
  332.         case LV_WORD:
  333.             /* -- append word to phrase, maybe -- */
  334.             ap_pappend (AP_GENERIC_WORD, buf);
  335.             break;
  336.  
  337.         case LV_AT:
  338.             /* -- mailbox (name) end -- */
  339.             if (!got_822) {
  340.                 r822_ptr = ap_sp;
  341.                 got_822 = TRUE;
  342.             }
  343.             ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX);
  344.             ap_palloc ();
  345.             state = STDOMAIN;
  346.             break;
  347.  
  348.         case LV_LESS:
  349.             /* -- person name end -- */
  350.             state = STSTPER;
  351.             break;
  352.  
  353.         case LV_COLON:
  354.             /* -- group name end -- */
  355.              if (ap_grplev++ >= 1 && ap_intype == AP_PARSE_822) {
  356.                 /* -- may not be nested -- */
  357.  
  358. #ifdef AP_DEBUG
  359.                 if (ap_debug)
  360.                     PP_DBG (("(intype=%d,ap_grplev=%d)",
  361.                         ap_intype,
  362.                         ap_grplev));
  363. #endif
  364.  
  365.                 state = STEBAD;
  366.                 break;
  367.              }
  368.             ap_sqtfix (ap_sp, ap_pcur, AP_GROUP_START);
  369.             ap_sp -> ap_obtype = AP_GROUP_NAME;
  370.             state = STITER;
  371.             break;
  372.  
  373.         case LV_SEMI:
  374.             ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX);
  375.             ap_sp -> ap_obtype = AP_MAILBOX;
  376.             state = STEGRP;
  377.             break;
  378.  
  379.         case LV_GRTR:
  380.             state = STEPER;
  381.             break;
  382.  
  383.         case LV_COMMA:
  384.             ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX);
  385.             state = STEOK;
  386.             break;
  387.         case LV_EOD:
  388.             ap_sqtfix (ap_sp, ap_pcur, AP_MAILBOX);
  389.             state = STEOK;
  390.             break;
  391.         case LV_COMMENT:
  392.             ap_pappend (AP_COMMENT, buf);
  393.             break;
  394.         default:
  395.             state = STEBAD;
  396.             break;
  397.         }
  398.  
  399.         continue;
  400.  
  401.  
  402. /* -------------------------  Address lists  ---------------------------- */
  403.  
  404.  
  405.     case STSTPER:
  406.         /* -- personal address list; no empty node -- */
  407.         if (ap_perlev++ > 0 && ap_intype == AP_PARSE_822) {
  408.             /* -- may not be nested -- */
  409. #ifdef AP_DEBUG
  410.             if (ap_debug)
  411.                 PP_DBG (("(intype=%d,ap_perlev=%d)",
  412.                     ap_intype,
  413.                     ap_perlev));
  414. #endif
  415.             state = STEBAD;
  416.             break;
  417.         }
  418.         ap_routing = OK;
  419.         ap_sqtfix (ap_sp, ap_pcur, AP_PERSON_START);
  420.         ap_sp -> ap_obtype = AP_PERSON_NAME;
  421.         state = STITER;
  422.         continue;
  423.  
  424.  
  425.     case STEPER:
  426.         if (--ap_perlev < 0) {
  427.  
  428. #ifdef AP_DEBUG
  429.             if (ap_debug)
  430.                 PP_DBG (("(ap_perlev=%d)", ap_perlev));
  431. #endif
  432.  
  433.             state = STEBAD;
  434.             break;
  435.         }
  436.         ap_pappend (AP_PERSON_END, NULLCP);
  437.         ap_palloc ();   /* SEK add storage */
  438.         state = STECMNT; /* allow comments, etc */
  439.         continue;
  440.  
  441.  
  442.     case STEGRP:
  443.         if (--ap_grplev < 0) {
  444.  
  445. #ifdef AP_DEBUG
  446.             if (ap_debug)
  447.                 PP_DBG (("(ap_grplev=%d)", ap_grplev));
  448. #endif
  449.  
  450.             state = STEBAD;
  451.             break;
  452.         }
  453.         ap_pappend (AP_GROUP_END, NULLCP);
  454.         state = STECMNT;
  455.         continue;
  456.  
  457.  
  458. /* --------------------------  Data type ---------------------------------- */
  459.  
  460.  
  461.     case STDTYPE:
  462.         /* -- data type name; empty node -- */
  463.         if (ap_intype == AP_PARSE_822) {
  464.             /* -- data types not legal in 822 -- */
  465.  
  466. #ifdef AP_DEBUG
  467.             if (ap_debug)
  468.                 PP_DBG (("(intype=%d)", ap_intype));
  469. #endif
  470.  
  471.             state = STEBAD;
  472.             break;
  473.         }
  474.  
  475.         if (ap_lex (buf, sizeof(buf)) != LV_WORD) {
  476.             state = STEBAD;
  477.             continue;
  478.         }
  479.         ap_pfill (AP_DATA_TYPE, buf);
  480.         state = STEDTYPE;
  481.         /* -- Just drop on through -- */
  482.  
  483.  
  484.     case STEDTYPE:
  485.         /* -- data type name end; empty node -- */
  486.         state = (ap_lex (buf, sizeof(buf)) == LV_COLON) ? STITER : STEBAD;
  487.         continue;
  488.  
  489.  
  490.  
  491. /* ---------------------------  domain  ----------------------------------- */
  492.  
  493.  
  494.     case STDOMAIN:
  495.         /* -- domain/host; no empty parse node -- */
  496.         switch (ap_lex (buf, sizeof(buf))) {
  497.         default:
  498.             state = STEBAD;
  499.             continue;
  500.         case LV_COMMENT:
  501.             ap_pappend (AP_COMMENT, buf);
  502.             continue;
  503.         case LV_DLIT:
  504.             ap_pappend (AP_DOMAIN_LITERAL, buf);
  505.             state = STEDOMAIN;
  506.             continue;
  507.         case LV_WORD:
  508.             ap_pfill (AP_DOMAIN, buf);
  509.             state = STEDOMAIN;
  510.         }
  511.  
  512.         /* -- just drop on through -- */
  513.  
  514.  
  515.     case STEDOMAIN:
  516.         /* -- domain end; no empty parse node -- */
  517.         switch (ap_lex (buf, sizeof(buf))) {
  518.         case LV_AT:
  519.             /* -- sequence of HOST's => @ separation -- */
  520.             if (r733_prefptr == NULLAP)
  521.                 r733_prefptr = ap_pcur;
  522.             ap_palloc ();
  523.             /* -- node which points to first routing ref -- */
  524.             state = STDOMAIN;
  525.             break;
  526.  
  527.         case LV_SEMI:
  528.             state = STEGRP;
  529.             break;
  530.         case LV_GRTR:
  531.             state = STEPER;
  532.             break;
  533.         case LV_COMMA:
  534.             if (ap_routing != DONE)
  535.                 state = STITER;
  536.             else
  537.                 state = STEOK;
  538.             break;
  539.         case LV_EOD:
  540.             if (ap_routing != DONE)
  541.                 state = STEBAD;
  542.             else
  543.                 state = STEOK;
  544.             break;
  545.         case LV_COMMENT:
  546.             ap_pappend (AP_COMMENT, buf);
  547.             break;
  548.         case LV_COLON:
  549.             if (ap_routing != DONE) {
  550.                 ap_routing = DONE;
  551.                 state = STITER;
  552.                 continue;
  553.             }
  554.             /* else drop on through */
  555.         default:
  556.             state = STEBAD;
  557.             break;
  558.         }
  559.  
  560.         continue;
  561.     }
  562.     }
  563. }
  564.  
  565.  
  566.  
  567. /* ------------------------------------------------------------------------ */
  568.  
  569.  
  570.  
  571. void ap_7to8 (r733_prefptr, r822_ptr)
  572. AP_ptr                  r733_prefptr,
  573.             r822_ptr;
  574. {
  575.     AP_ptr          routbase;
  576.     AP_ptr          ap;
  577.     char            *perneeded;
  578.  
  579.  
  580.     PP_DBG (("Lib/addr/ap_7to8()"));
  581.  
  582.     /* -- don't have to move it to 822 style -- */
  583.     if (r733_prefptr == NULLAP)   return;
  584.  
  585.     if (ap_pstrt -> ap_obtype == AP_MAILBOX) {
  586.         perneeded = strdup (r822_ptr -> ap_obvalue);
  587.         ap_pappend (AP_PERSON_END, NULLCP);
  588.     }
  589.     else
  590.         perneeded = NULLCP;
  591.  
  592.     /* -- move the sequence to newroute -- */
  593.     routbase = ap_alloc ();
  594.  
  595.     while (r733_prefptr -> ap_ptrtype != AP_PTR_NIL &&
  596.            r733_prefptr -> ap_ptrtype != AP_PTR_NXT &&
  597.            r733_prefptr -> ap_next != NULLAP) {
  598.  
  599.         switch (r733_prefptr -> ap_next -> ap_obtype) {
  600.         default:
  601.             /* -- only move domain info -- */
  602.             goto endit;
  603.  
  604.         case AP_COMMENT:
  605.             if (routbase -> ap_next != NULLAP) {
  606.                 /* -- try to append, not prepend, cmnts -- */
  607.                 PP_DBG (("comment appended'%s'",
  608.                        r733_prefptr->ap_next->ap_obvalue));
  609.                 (void) ap_move (routbase -> ap_next,
  610.                         r733_prefptr);
  611.                 continue;
  612.             }
  613.             /* else drop on through */
  614.  
  615.         case AP_DOMAIN_LITERAL:
  616.         case AP_DOMAIN:
  617.             PP_DBG (("val='%s'",
  618.                 r733_prefptr -> ap_next -> ap_obvalue));
  619.             (void) ap_move (routbase, r733_prefptr);
  620.             continue;
  621.         }
  622.     }
  623.  
  624.  
  625. endit:
  626.     /*
  627.     treatment here depends on whether we have an 822 route already.
  628.     Note that 822 pointer is NOT easy,  as an easy pointer was
  629.     too hard!
  630.     There is a need to copy first part of route to r822_ptr
  631.     */
  632.  
  633.     if (r822_ptr -> ap_obtype != AP_DOMAIN &&
  634.         r822_ptr -> ap_obtype != AP_DOMAIN_LITERAL) {
  635.  
  636.         ap_insert (r822_ptr, AP_PTR_MORE,
  637.                ap_new (r822_ptr -> ap_obtype,
  638.                r822_ptr -> ap_obvalue));
  639.  
  640.         free (r822_ptr -> ap_obvalue);
  641.  
  642.         ap_fllnode (r822_ptr, routbase -> ap_next -> ap_obtype,
  643.                 routbase -> ap_next -> ap_obvalue);
  644.  
  645.         (void) ap_sqinsert (r822_ptr, AP_PTR_MORE,
  646.                     routbase -> ap_next -> ap_next);
  647.  
  648.         /* -- add it before local-part -- */
  649.         ap_free (routbase -> ap_next);
  650.         ap_free (routbase);
  651.     }
  652.     else {
  653.         ap = r822_ptr;
  654.         while (ap -> ap_next -> ap_obtype == AP_DOMAIN ||
  655.                ap -> ap_next -> ap_obtype == AP_DOMAIN_LITERAL)
  656.                 ap = ap -> ap_next;
  657.         (void) ap_sqinsert (ap, AP_PTR_MORE, routbase -> ap_next);
  658.     }
  659.  
  660.  
  661.     /* -- need to kludge person name -- */
  662.     if (perneeded != 0) {
  663.         ap_insert (r822_ptr, AP_PTR_MORE,
  664.                ap_new (r822_ptr -> ap_obtype,
  665.                r822_ptr -> ap_obvalue));
  666.         free (r822_ptr -> ap_obvalue);
  667.         ap_fllnode (r822_ptr, AP_PERSON_NAME, perneeded);
  668.         free (perneeded);
  669.     }
  670. }
  671.